package com.ruoyi.system.service.impl;

import com.alibaba.dashscope.exception.NoApiKeyException;
import com.alibaba.dashscope.exception.UploadFileException;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonSyntaxException;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.photo.PhotoMetadataExtractor;
import com.ruoyi.system.domain.BusinessAnalysis;
import com.ruoyi.system.mapper.BusinessAnalysisMapper;
import com.ruoyi.system.service.IBusinessAnalysisService;
import com.ruoyi.system.util.DescriptionMatchingUtil;
import com.ruoyi.system.vo.AnalysisVo;
import com.ruoyi.system.vo.TranslateVo;
import com.ruoyi.system.vo.ZipFileVo;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.noear.snack.ONode;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * 文件解析Service业务层处理
 *
 * @author ruoyi
 * @date 2024-09-18
 */
@Service
public class BusinessAnalysisServiceImpl implements IBusinessAnalysisService {
    @Resource
    private BusinessAnalysisMapper businessAnalysisMapper;
    private static final Gson gson = new Gson();

    /**
     * 查询文件解析
     *
     * @param analysisId 文件解析主键
     * @return 文件解析
     */
    @Override
    public BusinessAnalysis selectBusinessAnalysisByAnalysisId(Long analysisId) {
        return businessAnalysisMapper.selectBusinessAnalysisByAnalysisId(analysisId);
    }

    /**
     * 查询文件解析列表
     *
     * @param vo 文件解析
     * @return 文件解析
     */
    @Override
    public List<BusinessAnalysis> selectBusinessAnalysisList(TranslateVo vo) {
        return businessAnalysisMapper.selectBusinessAnalysisList(vo);
    }

    /**
     * 新增文件解析
     *
     * @param businessAnalysis 文件解析
     * @return 结果
     */
    @Override
    public int insertBusinessAnalysis(BusinessAnalysis businessAnalysis) {
        businessAnalysis.setCreateTime(DateUtils.getNowDate());
        return businessAnalysisMapper.insertBusinessAnalysis(businessAnalysis);
    }

    @Override
    public AjaxResult zipFile(ZipFileVo zipFileVo) throws Exception {
        int fileType = zipFileVo.getFileType();
        if (fileType == 1) {
            ThumbnailsUtils.resizeImages(zipFileVo.getSourceFilePath(), zipFileVo.getTargetFilePath());
        } else if (fileType == 2) {
            VideoUtil.adjustVideoResolutions(zipFileVo.getSourceFilePath(), zipFileVo.getTargetFilePath());
        } else if (fileType == 3) {
            ThumbnailsUtils.resizeImagesAll(zipFileVo.getSourceFilePath(), zipFileVo.getTargetFilePath());
        } else if (fileType == 4) {
            VideoUtil.allVideoResolutions(zipFileVo.getSourceFilePath(), zipFileVo.getTargetFilePath());
        }
        return AjaxResult.success("成功");
    }

    @Override
    public AjaxResult delFile(String path, Integer type) throws Exception {

        if (type == 1) {
            ThumbnailsUtils.delAllImage(path);
        } else if (type == 2) {
            VideoUtil.delAllVedio(path);
        } else if (type == 3) {
            ThumbnailsUtils.delAlltxt(path);
        }
        return AjaxResult.success("成功");
    }

    @Override
    public AjaxResult fileOptimization(String path, String fileCatagory) {

        return null;
    }

    @Override
    public AjaxResult analysis(AnalysisVo vo) throws Exception {
        String filePath = URLDecoder.decode(vo.getFilePath(), "utf-8");
        File folder = new File(filePath);
        TranslateVo translateVo = new TranslateVo();

        translateVo.setFileCatagory(vo.getFileCatagory());
        List<BusinessAnalysis> analysisList = businessAnalysisMapper.selectBusinessAnalysisList(translateVo);
        List<String> sourcePathList = analysisList.stream().map(BusinessAnalysis::getSourceFilePath).collect(Collectors.toList());
        // 指定要遍历的根目录路径
        Path rootPath = Paths.get(filePath);
        // 遍历根目录下的所有文件和文件夹

        Files.walk(rootPath)
                .filter(Files::isRegularFile) // 过滤出普通文件
                .forEach(path -> {
                    File file = path.toFile();
                    String absolutePath = file.getAbsolutePath();
                    String sourceFileName = FilenameUtils.getName(absolutePath);
                    if (!sourcePathList.contains(absolutePath) && !absolutePath.contains(".txt")) {
                        String prompts = vo.getDescription();
                        //多轮单轮
                        if(StringUtils.isEmpty(prompts)){
                            prompts = "\n" +
                                    "请对以下图片进行深入解析，输出需包括三部分内容：标签（tag）、描述（caption）、单轮问答(conversations_songle)以及多轮问答（conversations_multi）。请严格按照以下格式与要求执行，输出结果为一个 JSON 对象。\n" +
                                    "输出格式要求如下：\n" +
                                    "{\n" +
                                    "  \"tag\": \"\",\n" +
                                    "  \"caption\": \"\",\n" +
                                    "  \"conversations_songle\":[\n" +
                                    "        {\n" +
                                    "          \"question\":\"\",\n" +
                                    "          \"answer\":\"\",\n" +
                                    "           \"type\":\"\"\n" +
                                    "        }\n" +
                                    "    ],\n" +
                                    "  \"conversations_multi\": [\n" +
                                    "    {\n" +
                                    "      \"question\": \"\",\n" +
                                    "      \"answer\": \"\"\n" +
                                    "    },\n" +
                                    "    {\n" +
                                    "      \"question\": \"\",\n" +
                                    "      \"answer\": \"\"\n" +
                                    "    },\n" +
                                    "    {\n" +
                                    "      \"question\": \"\",\n" +
                                    "      \"answer\": \"\"\n" +
                                    "    }\n" +
                                    "  ]\n" +
                                    "}\n" +
                                    "具体要求如下：\n" +
                                    "1. **标签（tag）提取**：\n" +
                                    "- 提取图像中所有明确可识别的实体类别，如：动植物、人物、交通工具、器物等；\n" +
                                    "- 标签应全面、具体、准确，涵盖图片中所有主要对象，使用逗号分隔；\n" +
                                    "- 示例：猫, 狗, 树, 自行车。\n" +
                                    "\n" +
                                    "2. **描述（caption）撰写**：\n" +
                                    "- 采用“总分结构”进行描述，字数不少于250字；\n" +
                                    "- **总述部分**：逻辑清晰地总结整张图片的主要内容，具备整体观察力；\n" +
                                    "- **细节部分**：深入描绘画面元素，包括但不限于图片类型、意图、所有物体、属性、数量、位置、关系、文字、前后景、环境等信息。\n" +
                                    "- 写作格式示例：这幅图整体概括为……；细节描述为……\n" +
                                    "3. **单轮问答（conversations_songle）生成**：\n" +
                                    "- 基于图中元素结合百科知识进行的推理性问答（inference）。\n" +
                                    "- 问答都与图片有关，问题必须通过看图才能回答，不通过图就可以回答的属于无效数据。\n" +
                                    "- 推理性问答在回答中要给出推理和运用常识知识的过程，答案长度不低于50个字，问题不低于10个字。\n" +
                                    "4. **多轮问答（conversations_multi）生成**：\n" +
                                    "- 多轮问答的每一轮问题和答案都与图片内容描述有关，问题必须通过图片内容才能回答，禁止推理。\n" +
                                    "- 生成不少于3轮连续问答，每轮为一个 question-answer 对象；三个问题之间必须有关联性和连续性，前后轮次之间没有关系的属于无效数据。 \n" +
                                    "- 第一轮问答基于图像的内容细致观察提出问题并作答。\n" +
                                    "- 从第二轮开始，之后的每轮问题必须紧密关联上一轮的回答，必须从上一轮的回答内容中提取出本轮的问题，第一轮之后的问题中不涵盖主体名称，形成残缺问题，不能独立形成问题，但是在回答中可以出现主体名称，形成清晰的逻辑链条；\n" +
                                    "- 后续问题不可独立理解和解答，必须依赖上一轮回答内容；\n" +
                                    "- 每轮问题与回答字数不得少于20字，回答需具有观察力、分析性与逻辑性，避免模板化内容。\n" +
                                    "注意事项：\n" +
                                    "- 所有问题和回答不能重复或者相似。\n" +
                                    "- 所有问题提问的要具有一定专业水准。\n" +
                                    "- 所有回答要适当润色，保证答案表述的清晰完整。\n" +
                                    "- 所有内容必须中文输出\n" +
                                    "- 所有内容需语言表达清晰流畅，具备知识性与可读性；\n" +
                                    "- 请避免冗余，确保表达准确、富有洞察；\n" +
                                    "- 最终输出必须为有效的 JSON 格式结构，确保程序可解析。";
                        }

//                        String parentPathName = path.getParent().getFileName().toString();
//                        if (StringUtils.isNotEmpty(parentPathName)) {
//                            prompts = prompts.replaceAll("object", parentPathName);
//                        }
                        if(vo.getAnalysisCatagory()==3||vo.getAnalysisCatagory()==4){
                            //视频解析获取视频时长
                            String duration = null;
                            try {
                                duration = FFmpegDurationChecker.getDurationWithFFmpeg(file);
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                            if (StringUtils.isNotEmpty(duration)) {
                                prompts = prompts.replaceAll("object", duration);
                                vo.setDescription(prompts);
                            }
                        }

                        vo.setDescription(prompts);
                        extractedAnalysis(vo, file, absolutePath, sourceFileName);
                    }

                });
        return AjaxResult.success("成功");
    }

    @Override
    public AjaxResult photoAnalysis(AnalysisVo vo) throws Exception {
        String filePath = URLDecoder.decode(vo.getFilePath(), "utf-8");

        TranslateVo translateVo = new TranslateVo();

        translateVo.setFileCatagory(vo.getFileCatagory());
        List<BusinessAnalysis> analysisList = businessAnalysisMapper.selectBusinessAnalysisList(translateVo);
        List<String> sourcePathList = analysisList.stream().map(BusinessAnalysis::getSourceFilePath).collect(Collectors.toList());
        // 指定要遍历的根目录路径
        Path rootPath = Paths.get(filePath);
        // 遍历根目录下的所有文件和文件夹

        Files.walk(rootPath)
                .filter(Files::isRegularFile) // 过滤出普通文件
                .forEach(path -> {
                    File file = path.toFile();
                    String absolutePath = file.getAbsolutePath();
                    String sourceFileName = FilenameUtils.getName(absolutePath);
                    if (!sourcePathList.contains(absolutePath) && !absolutePath.contains(".txt")) {
                        extractedAnalysis(vo, file, absolutePath, sourceFileName);
                    }

                });
        return AjaxResult.success("成功");
    }


    private synchronized void extractedAnalysis(AnalysisVo vo, File file, String absolutePath, String sourceFileName) {
        try {
            Thread.sleep(320);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            String result = null;
            try {


                result = QwUtil.conversationCall(file.getAbsolutePath(), vo.getDescription(), vo.getAnalysisCatagory());
            } catch (NoApiKeyException e) {
                System.out.println(e);
                throw new RuntimeException(e);
            } catch (UploadFileException e) {
                System.out.println(e);
                throw new RuntimeException(e);
            }
            ONode oNode = ONode.load(result);
            ONode node = oNode.select("$.output.choices[0].message.content[0].text");
            //tokens 计算
            Integer input_tokens = oNode.select("$.usage.input_tokens").getInt();
            Integer output_tokens = oNode.select("$.usage.output_tokens").getInt();
            Integer onceTokens = input_tokens + output_tokens;

            BusinessAnalysis analysis = new BusinessAnalysis();
            analysis.setAnalysis(vo.getDescription());
            if (vo.getAnalysisCatagory().equals(1) || vo.getAnalysisCatagory().equals(2)) {
                analysis.setAnalysisType(1);
            } else if (vo.getAnalysisCatagory().equals(3) || vo.getAnalysisCatagory().equals(4)) {
                analysis.setAnalysisType(2);
            }
            analysis.setAnalysisCatagory(vo.getAnalysisCatagory());
            analysis.setFileCatagory(vo.getFileCatagory());
            analysis.setSourceFileName(sourceFileName);
            analysis.setSourceFilePath(absolutePath);
            String zhAnalysis = node.getString();
            zhAnalysis = zhAnalysis.replace("-", "");
            //添加描述匹配
            zhAnalysis = DescriptionMatchingUtil.descriptionMatch(analysis.getSourceFilePath(), zhAnalysis);
            analysis.setZhAnalysis(zhAnalysis);
            analysis.setZhAnalysis(zhAnalysis);
            analysis.setStatus(1);
            analysis.setInputTokens(input_tokens);
            analysis.setOutputTokens(output_tokens);
            analysis.setTotalTokens(onceTokens);
            analysis.setCreateTime(DateUtils.getNowDate());
            businessAnalysisMapper.insertBusinessAnalysis(analysis);
        }).start();
    }

    @Override
    public AjaxResult translate(TranslateVo vo) throws Exception {
//        vo.setStatus(1);
        List<BusinessAnalysis> analysisList = businessAnalysisMapper.findAnalysisList(vo);
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (BusinessAnalysis analysis : analysisList) {
            executorService.submit(() -> {
                String zhAnalysis = analysis.getZhAnalysis();
                String zhAnalysisTrans = zhAnalysis;
                if (StringUtils.isNotEmpty(zhAnalysis)) {
                    zhAnalysisTrans = zhAnalysis.substring(zhAnalysis.indexOf("中文描述：") + 5);
//                try {
//                    Thread.sleep(1000); // 延迟1秒
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                    String trans = null;
                    try {
                        GT g = GT.getInstance();
                        ;

                        trans = g.translateText(zhAnalysisTrans, "zh_cn", "en");
                        System.out.println(trans);
//                        trans = TranslateUtil.translate(zhAnalysisTrans);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                    if (StringUtils.isNotEmpty(trans) && !trans.equals("null")) {
                        analysis.setEnAnalysis(trans);
                        analysis.setStatus(0);
                        analysis.setUpdateTime(DateUtils.getNowDate());
                        String targetFileName = FilenameUtils.getBaseName(analysis.getSourceFilePath()) + ".txt";
                        String path = FilenameUtils.getFullPath(analysis.getSourceFilePath()) + FilenameUtils.getBaseName(analysis.getSourceFilePath()) + ".txt";
                        analysis.setTargetFilePath(path);
                        analysis.setTargetFileName(targetFileName);

                        businessAnalysisMapper.updateBusinessAnalysis(analysis);
////                    File file = new File(path);
////                    int keywordIndex = zhAnalysis.indexOf("中文描述");
////                    String tag = zhAnalysis.substring(0, keywordIndex);
////                    StringBuffer sb = new StringBuffer(tag);
////                    sb.append(System.lineSeparator()).append("中文描述：").append(System.lineSeparator()).append(zhAnalysisTrans).append(System.lineSeparator()).append("英文描述：").append(System.lineSeparator()).append(trans);
////
////                    FileUtils.writeStringToFile(file, sb.toString(), "UTF-8");
                    }

                }
            });


        }
        return AjaxResult.success("成功");
    }

    @Override
    public AjaxResult fileOutPut(TranslateVo vo) throws Exception {

        List<BusinessAnalysis> analysisList = businessAnalysisMapper.findAnalysisList(vo);
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        for (BusinessAnalysis analysis : analysisList) {
            String zhAnalysis = analysis.getZhAnalysis();
//            去人种肤色

//            if(zhAnalysis.contains("白种")){
//                zhAnalysis=zhAnalysis.replaceAll("白种","");
//            }else if(zhAnalysis.contains("黑种")){
//                zhAnalysis=zhAnalysis.replaceAll("黑种","");
//            }else if(zhAnalysis.contains("黄种")){
//                zhAnalysis=zhAnalysis.replaceAll("黄种","");
//            }else if(zhAnalysis.contains("棕种")){
//                zhAnalysis=zhAnalysis.replaceAll("棕种","");
//            }else if(zhAnalysis.contains("白肤色")){
//                zhAnalysis=zhAnalysis.replaceAll("白肤色","");
//            }else if(zhAnalysis.contains("黑肤色")){
//                zhAnalysis=zhAnalysis.replaceAll("黑肤色","");
//            }else if(zhAnalysis.contains("黄肤色")){
//                zhAnalysis=zhAnalysis.replaceAll("黄肤色","");
//            }else if(zhAnalysis.contains("棕肤色")){
//                zhAnalysis=zhAnalysis.replaceAll("棕肤色","");
//            }
            String zhAnalysisTrans = "";
            if (StringUtils.isNotEmpty(zhAnalysis)) {

                if (!isValidJson(zhAnalysis)) {
                    zhAnalysisTrans = extractJson(zhAnalysis);
                } else {
                    zhAnalysisTrans = zhAnalysis;
                }


//                zhAnalysisTrans = zhAnalysis.substring(zhAnalysis.indexOf("中文描述：") + 5);
//
//
//
                String path = FilenameUtils.getFullPath(analysis.getSourceFilePath()) + FilenameUtils.getBaseName(analysis.getSourceFilePath()) + ".json";
                File file = new File(path);
//                int keywordIndex = zhAnalysis.indexOf("中文描述");
//                String tag = "";
//                if (keywordIndex != -1) {
//                    tag = zhAnalysis.substring(0, keywordIndex);
//                    tag = tag.replace("\n", "");
//                    tag = SentenceFormatter.removePunctuation(tag);
//                    if (tag.contains("标签")) {
//                        tag = tag.substring(3);
//                    }
//
//                }
                StringBuffer sb = new StringBuffer();
                sb.append(zhAnalysisTrans.trim());

//                if (StringUtils.isNotEmpty(tag)) {
//
//                    sb.append(System.lineSeparator()).append(zhAnalysisTrans.trim());
//
//                } else {
//                    sb.append(zhAnalysisTrans.trim());
//                }
//                if(StringUtils.isNotEmpty(analysis.getEnAnalysis())){
//                    sb.append(System.lineSeparator()).append(SentenceFormatter.capitalizeFirstLetter(analysis.getEnAnalysis()).trim());
//                }

                FileUtils.writeStringToFile(file, sb.toString(), "UTF-8");
                if (ThumbnailsUtils.countsChinese(zhAnalysisTrans) < 30) {
                    String path2 = "E:\\workdata\\码诚科技\\采集翻译\\正式对接\\王芳\\本地";
                    String localPath = path2 + "\\字数小30" + file.getParent().toString().substring(path2.length());
                    File outputDir = new File(localPath);
                    // 如果文件夹不存在，则创建文件夹
                    if (!outputDir.exists()) {
                        outputDir.mkdirs();
                    }
                    String savePath = localPath + "\\" + file.getName();
                    File file2 = new File(savePath);
                    org.apache.commons.io.FileUtils.writeStringToFile(file2, sb.toString(), "UTF-8");

                }
            }

        }


        return AjaxResult.success("成功");
    }

    /**
     * 拍照大师导出
     *
     * @param vo
     * @return
     * @throws Exception
     */
    @Override
    public AjaxResult photoFileOutPut(TranslateVo vo) throws Exception {
        List<BusinessAnalysis> analysisList = businessAnalysisMapper.findAnalysisList(vo);
        for (BusinessAnalysis analysis : analysisList) {
            String zhAnalysis = analysis.getZhAnalysis();
            String zhAnalysisTrans = "";
            if (StringUtils.isNotEmpty(zhAnalysis)) {

                if (!isValidJson(zhAnalysis)) {
                    zhAnalysisTrans = extractJson(zhAnalysis);
                } else {
                    zhAnalysisTrans = zhAnalysis;
                }
                //修改照片属性
//                焦段	焦距
//                光圈值	光圈值
//                感光度	ISO速度
//                快门速度	曝光时间
//                曝光补偿	曝光补偿
//                自动白平衡	白平衡

//                "拍摄参数": {
//                    "焦段": "50mm",
//                            "光圈值": "f/2.8",
//                            "感光度": "ISO 100",
//                            "快门速度": "1/200s",
//                            "曝光补偿": "+0.3EV",
//                            "自动白平衡值": "日光",
//                            "摄影师位置": "正面稍低角度",
//                            "拍摄方向": "正对主体"
//                }
//                params.put("焦段", "N/A");
//                params.put("光圈值", "N/A");
//                params.put("感光度", "N/A");
//                params.put("快门速度", "N/A");
//                params.put("曝光补偿", "N/A");
//                params.put("自动白平衡值", "N/A");
//                params.put("拍摄方向", "N/A");
//                params.put("摄影师位置", "N/A");
                File photoFile = new File(analysis.getSourceFilePath());
                Map<String, String> photoDataMap = PhotoMetadataExtractor.extractShootingParams(photoFile);

                ONode oNode = ONode.load(zhAnalysisTrans);
                oNode.select("$.拍摄参数.焦段").val(photoDataMap.get("焦段"));
                oNode.select("$.拍摄参数.光圈值").val(photoDataMap.get("光圈值"));
                oNode.select("$.拍摄参数.感光度").val(photoDataMap.get("感光度"));
                oNode.select("$.拍摄参数.快门速度").val(photoDataMap.get("快门速度"));
                oNode.select("$.拍摄参数.曝光补偿").val(photoDataMap.get("曝光补偿"));
                oNode.select("$.拍摄参数.自动白平衡值").val(photoDataMap.get("自动白平衡值"));

                String json = oNode.toString();

                String path = FilenameUtils.getFullPath(analysis.getSourceFilePath()) + FilenameUtils.getBaseName(analysis.getSourceFilePath()) + ".json";
                File file = new File(path);

                StringBuffer sb = new StringBuffer();
                sb.append(json.trim());


                FileUtils.writeStringToFile(file, sb.toString(), "UTF-8");
            }

        }


        return AjaxResult.success("成功");
    }

    @Override
    public AjaxResult folderOutPut(TranslateVo vo) throws Exception{
        List<BusinessAnalysis> analysisList = businessAnalysisMapper.findAnalysisList(vo);

        for (BusinessAnalysis analysis : analysisList) {
            String zhAnalysis = analysis.getZhAnalysis();
            String sourcePath = analysis.getSourceFilePath();
            StringBuffer zhAnalysisTrans = new StringBuffer();
            if (StringUtils.isNotEmpty(zhAnalysis)) {

                if (!isValidJson(zhAnalysis)) {
                    zhAnalysisTrans.append(extractJson(zhAnalysis).trim()) ;
                } else {
                    zhAnalysisTrans.append(zhAnalysis) ;
                }
                // 使用Gson解析JSON（替代JSONObject）
                Map<String, String> stringStringMap = gson.fromJson(zhAnalysisTrans.toString(),
                        new com.google.gson.reflect.TypeToken<LinkedHashMap<String, String>>(){}.getType());

                // 提取维度值
                String scene = stringStringMap.getOrDefault("拍摄场景", "未知");
                String distance = stringStringMap.getOrDefault("拍摄距离", "未知");
                String light = stringStringMap.getOrDefault("拍摄光线", "未知");
                String angle = stringStringMap.getOrDefault("拍摄角度", "未知");
                String wear = stringStringMap.getOrDefault("人物穿戴", "未知");
                // 创建目标文件夹名称
                String folderName = String.format("%s_%s_%s_%s_%s",
                        scene, distance, light, angle, wear);

                // 从源路径提取上级目录（作为根文件夹）
                Path sourceFilePath = Paths.get(sourcePath);
                Path parentDir = sourceFilePath.getParent().getParent();
                String rootDirName = parentDir.getFileName().toString();

                // 创建目标文件夹路径
                Path targetDir = parentDir.resolve(folderName);

                // 创建目标文件夹（如果不存在）
                if (!Files.exists(targetDir)) {
                    Files.createDirectories(targetDir);
                    System.out.println("创建文件夹: " + targetDir);
                }

                // 移动文件到目标文件夹
                Path targetFile = targetDir.resolve(sourceFilePath.getFileName());
                Files.copy(sourceFilePath, targetFile, StandardCopyOption.REPLACE_EXISTING);
                System.out.println("移动文件: " + sourceFilePath);
                System.out.println("    到: " + targetFile);
                System.out.println("--------------------------------------------");
            }
        }
        return AjaxResult.success("成功");
    }

    /**
     * 截取字符串中第一个[和最后一个]之间的内容
     *
     * @param input 原始字符串
     * @return 截取后的子字符串
     * @throws IllegalArgumentException 当格式不符合要求时抛出异常
     */
    public static String extractJson(String input) {
        // 校验输入有效性
        if (input == null || input.isEmpty()) {
            throw new IllegalArgumentException("输入字符串不能为空");
        }

        int startZIndex = input.indexOf('[');
        int endZIndex = input.lastIndexOf(']');
        int startBIndex = input.indexOf('{');
        int endBIndex = input.lastIndexOf('}');
        int startIndex = 0;
        int endIndex =input.length()-1;

        if(startZIndex>=0&&startBIndex>=0){
            if(startZIndex<startBIndex){
                startIndex = startZIndex;
            }else{
                startIndex = startBIndex;
            }
        }else if(startZIndex==-1&&startBIndex>=0){
            startIndex = startBIndex;
        }

        if(endZIndex>=0&&endBIndex>=0){
            if(endZIndex<endBIndex){
                endIndex = endBIndex;
            }else{
                endIndex = endZIndex;
            }
        }else if(endZIndex==-1&&endBIndex>=0){
            endIndex = endBIndex;
        }


        // 检查括号位置有效性
        if (startIndex == -1 || endIndex == -1) {
            throw new IllegalArgumentException("未找到有效的方括号");
        }
        if (startIndex >= endIndex) {
            throw new IllegalArgumentException("方括号位置不匹配");
        }

        // 截取内容（包含方括号内的全部内容）
        return input.substring(startIndex, endIndex + 1);
    }

    /**
     * 验证字符串是否为合法JSON
     *
     * @param json 待验证字符串
     * @return true表示合法，false不合法
     */
    public static boolean isValidJson(String json) {
        if (json == null || json.isEmpty()) {
            return false;
        }

        // 快速判断首尾字符
        String trimmed = json.trim();
        if (!(trimmed.startsWith("{") && trimmed.endsWith("}")) &&
                !(trimmed.startsWith("[") && trimmed.endsWith("]"))) {
            return false;
        }

        try {
            // 使用Gson深度解析
            gson.fromJson(trimmed, JsonElement.class);
            return true;
        } catch (JsonSyntaxException ex) {
            return false;
        }
    }

    /**
     * 修改文件解析
     *
     * @param businessAnalysis 文件解析
     * @return 结果
     */
    @Override
    public int updateBusinessAnalysis(BusinessAnalysis businessAnalysis) {
        businessAnalysis.setUpdateTime(DateUtils.getNowDate());
        return businessAnalysisMapper.updateBusinessAnalysis(businessAnalysis);
    }

    /**
     * 批量删除文件解析
     *
     * @param analysisIds 需要删除的文件解析主键
     * @return 结果
     */
    @Override
    public int deleteBusinessAnalysisByAnalysisIds(String analysisIds) {
        return businessAnalysisMapper.deleteBusinessAnalysisByAnalysisIds(Convert.toStrArray(analysisIds));
    }

    /**
     * 删除文件解析信息
     *
     * @param analysisId 文件解析主键
     * @return 结果
     */
    @Override
    public int deleteBusinessAnalysisByAnalysisId(Long analysisId) {
        return businessAnalysisMapper.deleteBusinessAnalysisByAnalysisId(analysisId);
    }
}
